#pragma once
#include <iostream>
#include <string>
#include <functional>
#include "Reactor.hpp"
#include "InetAddr.hpp"

// 封装文件描述符
// 1.给每个文件描述符做一个设计，保证每一个文件描述符都有一个自己的接收缓冲区，
// 之后，在epoll当中，就没有文件描述符的概念，包括套接字，一起被封装成为连接：connection

class Connection;
class Reactor;
using handler_t = std::function<void(Connection *conn)>;

#define ListenConnection 0
#define NormalConnection 1

// 未来我们的服务器，一切都是Connection， 对我们来讲：listensockfd也是一样
class Connection
{

public:
    Connection(int sockfd) : _sockfd(sockfd)
    {
    }

    // 注册对应的事件处理方法
    void RegisterHandler(handler_t recver, handler_t sender, handler_t excepter)
    {
        _handler_recver = recver;
        _handler_sender = sender;
        _handler_excepter = excepter;
    }

    void SetEvents(uint32_t events)
    {
        _events = events;
    }
    uint32_t Events()
    {
        return _events;
    }
    void SetConnectionType(int type)
    {
        _type = type;
    }
    int Type()
    {
        return _type;
    }
    int Sockfd()
    {
        return _sockfd;
    }
    void SetReactor(Reactor *R)
    {
        _R = R;
    }
    void SetAddr(const InetAddr &addr)
    {
        _addr = addr;
    }

    void AppendInbuffer(const std::string &in)
    {
        _inbuffer += in;
    }
    std::string &Inbuffer()
    {
        return _inbuffer;
    }

    void AppendOutbuffer(const std::string &in)
    {
        _outbuffer += in;
    }
    std::string &Outbuffer()
    {
        return _outbuffer;
    }

    void DiscardOutbuffer(int n)
    {
        _outbuffer.erase(0, n); // 从0开始移除n个字节
    }

    void Close()
    {
        if (_sockfd >= 0)
            ::close(_sockfd);
    }

    ~Connection() {}

private:
    int _sockfd;

    uint32_t _events; // 所关心的事件

    std::string _inbuffer; // 使用string来充当缓冲区只能满足此代码的需求（在网络通信中传二进制，就不行）
    std::string _outbuffer;
    // 套接字类型
    int _type;
    // 正常来讲，是不能暴露出来的，这里偷懒处理
    InetAddr _addr; // 客户端的套接字信息
public:
    handler_t _handler_recver;   // 处理读取
    handler_t _handler_sender;   // 处理写入
    handler_t _handler_excepter; // 处理异常

    // 定义一个Reactor指针，实现connection和reactor之间的互相引用
    // 回指向自己所属的Reactor
    Reactor *_R;
};
